(function () {
  // 首先还是封装两个 DOM 查询的方法
  function $(select) {
    return document.querySelector(select);
  }
  function $$(select) {
    return document.querySelectorAll(select);
  }

  const gobangTable = $(".gobang-table"); // 获取棋盘的 table
  let pieces = []; // 棋子列表
  let playingChess = true; // 是否正在下棋
  let color = 1; // 棋子颜色：1为黑0，-1为白
  const sizeNumber = 16; // 棋盘大小（行/列的数量）

  /**
   * 每个网格是一个td元素，每个棋子是一个div元素，div在td里面，也就是棋子在网格内部，然后通过定位将棋子顶到网格边界线上
   * 棋子需要落在网格线上，于是可设每一个网格对应一个棋子，棋子在网格的左上角定位
   * 然后对最右侧网格线和最底部网格线以及右下角那个点单独做处理
   * 也就是说最下面的一行网格里面和最右侧一列网格里面最多会有两个棋子，而右下角的网格里面最多会有四个棋子，其余的网格里面都最多有一个棋子
   */

  // 初始化布局
  function initLayout() {
    let html = "";
    for (let i = 0; i < sizeNumber; i++) {
      html += `<tr>`;
      for (let j = 0; j < sizeNumber; j++) {
        // data-row和data-column表示第几行第几列，也等价于网格td的上边线和左边线分别是边线中的第几条
        html += `<td data-row='${i}' data-column='${j}'></td>`;
      }
      html += `</tr>`;
    }
    gobangTable.innerHTML = html;
  }

  // 初始化事件
  function initEvent() {
    gobangTable.addEventListener("click", onGobangTableClick);
  }

  // 恢复棋盘
  function restore() {
    initLayout(); // 重新初始化布局
    pieces = []; // 置空棋子列表
    playingChess = true; // 重新开始游戏
  }

  // 点击事件
  function onGobangTableClick(e) {
    // 事件委托
    if (e.target.tagName === "TD") {
      // 点击的是TD
      if (playingChess) {
        // 正在下棋
        const tdLayoutInfo = e.target.dataset;
        const tdSize = e.target.clientWidth;

        // x，y表示棋子在第x条列线和第y条列线的交点
        // offset表示当前点距离父元素的距离
        const pieceInfo = {
          x:
            e.offsetX > tdSize / 2
              ? +tdLayoutInfo.column + 1
              : +tdLayoutInfo.column,
          y: e.offsetY > tdSize / 2 ? +tdLayoutInfo.row + 1 : +tdLayoutInfo.row,
          con: e.target,
          color: color == 1 ? "black" : "white",
        };

        pieceDown(pieceInfo); // 将该棋子落下
      } else {
        // 未在下棋，说明游戏已经结束
        if (confirm("是否重新开始？")) {
          restore();
        }
      }
    }
  }

  // 棋子落下：设置棋子坐标，并将棋子添加到DOM与pieces中
  function pieceDown(pieceInfo) {
    if (isExist(pieceInfo) || !playingChess) {
      // 如果总容器gobangTable当前位置存在棋子或者游戏未在运行则不执行
      return;
    }

    console.log("落子", pieceInfo);

    const { x, y } = pieceInfo;

    // 生成一个棋子，其实就是生成一个 div，然后将该 div 放入到对应的 td 里面
    const newPiece = `<div data-index='${pieces.length}' data-x='${x}' data-y='${y}'  class="piece ${pieceInfo.color}"></div>`;

    if (x < sizeNumber && y < sizeNumber) {
      // 找到棋子需要插入到的网格容器td
      const conTd = $(`td[data-row='${y}'][data-column='${x}']`);
      conTd.innerHTML += newPiece;
    }

    // 棋子落在最右侧线上
    if (x == sizeNumber && y < sizeNumber) {
      // 找到棋子需要插入到的网格容器td
      const conTd = $(`td[data-row='${y}'][data-column='${x - 1}']`);
      conTd.innerHTML += newPiece;
      conTd.lastChild.style.left = "100%";
    }

    // 棋子落在最下侧线上
    if (x < sizeNumber && y == sizeNumber) {
      // 找到棋子需要插入到的网格容器td
      const conTd = $(`td[data-row='${y - 1}'][data-column='${x}']`);
      conTd.innerHTML += newPiece;
      conTd.lastChild.style.top = "100%";
    }

    // 棋子落在右下角上
    if (x == sizeNumber && y == sizeNumber) {
      // 找到棋子需要插入到的网格容器td
      const conTd = $(`td[data-row='${y - 1}'][data-column='${x - 1}']`);
      conTd.innerHTML += newPiece;
      conTd.lastChild.style.left = "100%";
      conTd.lastChild.style.top = "100%";
    }

    pieces.push(pieceInfo);
    color = -color; // 反转颜色

    // 检查是否结束
    checkOver();
  }

  // 检查棋子是否存在
  function isExist(pieceInfo) {
    return pieces.find(
      (item) => item.x == pieceInfo.x && item.y == pieceInfo.y
    );
  }

  /**
   * 获得以当前节点为起点的五子DOM
   * @param {pieceInfo} current 当前节点
   * @param {String} direction 查找方向：row|column|leftTop（“ \ ”这种方向）|rightTop（“ / ”这种方向）
   * @return {*}
   */
  function getList(current, direction) {
    const list = []; // 存放列表
    // 先将当前这个添加
    list.push($(`.piece[data-x='${current.x}'][data-y='${current.y}']`));

    // 查找剩余的四个
    for (let i = 1; i <= 4; i++) {
      let findItem;
      if (direction == "row") {
        findItem = $(
          `.piece[class*='${current.color}'][data-x='${
            current.x + i
          }'][data-y='${current.y}']`
        );
      } else if (direction == "column") {
        findItem = $(
          `.piece[class*='${current.color}'][data-x='${current.x}'][data-y='${
            current.y + i
          }']`
        );
      } else if (direction == "leftTop") {
        findItem = $(
          `.piece[class*='${current.color}'][data-x='${
            current.x + i
          }'][data-y='${current.y + i}']`
        );
      } else if (direction == "rightTop") {
        findItem = $(
          `.piece[class*='${current.color}'][data-x='${
            current.x + i
          }'][data-y='${current.y - i}']`
        );
      }

      if (!findItem) {
        // 一项未找到就直接return
        return false;
      }
      list.push(findItem);
    }

    return list;
  }

  // 检查游戏是否结束：五子连棋
  function checkOver() {
    for (let i = 0; i < pieces.length; i++) {
      const current = pieces[i];

      // 依次进行四个方向的获取与判断
      const rowList = getList(current, "row");
      if (rowList && rowList.length == 5) {
        over(rowList, current.color);
        return;
      }

      const colList = getList(current, "column");
      if (colList && colList.length == 5) {
        over(colList, current.color);
        return;
      }

      const leftTopList = getList(current, "leftTop");
      if (leftTopList && leftTopList.length == 5) {
        over(leftTopList, current.color);
        return;
      }

      const rightTopList = getList(current, "rightTop");
      if (rightTopList && rightTopList.length == 5) {
        over(rightTopList, current.color);
        return;
      }
    }
  }

  // 结束函数：winList代表获胜的五个棋子列表，color代表胜方颜色
  function over(winList, color) {
    playingChess = false; // 停止游戏

    // 遍历所有棋子显示其下子顺序
    $$(".piece").forEach((item) => {
      item.innerText = +item.dataset.index + 1;
    });

    // 遍历获胜的五子添加winner类名
    winList.forEach((item) => {
      item.classList.add("winner");
    });

    setTimeout(() => {
      if (
        confirm(`恭喜${color == "white" ? "白子" : "黑子"}胜利！是否再来一局？`)
      ) {
        // 重新开始
        restore();
      }
    }, 0);
  }

  function main() {
    initLayout();
    initEvent();
  }

  main();
})();
